package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;


import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domin.dto.LearningPlanDTO;
import com.tianji.learning.domin.po.LearningLesson;
import com.tianji.learning.domin.vo.LearningLessonVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author 金山
 * @since 2025-10-18
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
    private final CourseClient courseClient;

    private final CatalogueClient catalogueClient;

    /**
     * 1.添加课程到用户课表
     *
     * @param userId
     * @param courseIds
     */
    @Override
    @Transactional
    public void addLessons(Long userId, List<Long> courseIds) {
        //1.根据课程ID集合 远程调用 查询课程信息（课程有效期）
        List<CourseSimpleInfoDTO> conrseInfoList = courseClient.getSimpleInfoList(courseIds);
        if (ObjectUtil.isEmpty(conrseInfoList)) {
            log.error("课程信息不存在");
            return;
        }

        //2.遍历课程集合，组装课表数据
        List<LearningLesson> lessons = new ArrayList<>();
        for (CourseSimpleInfoDTO courseInfo : conrseInfoList) {
            LearningLesson lesson = new LearningLesson();
            //2.1 填充user ID coueseID
            lesson.setUserId(userId);
            lesson.setCourseId(courseInfo.getId());

            //2.2 填充课程过期时间
            Integer validDuration = courseInfo.getValidDuration();
            if (ObjectUtil.isEmpty(validDuration) || validDuration <= 0) {
                //跳出
                continue;
            }
            lesson.setExpireTime(LocalDateTime.now().plusMonths(validDuration));
            lessons.add(lesson);
        }

        //3.批量新增
        this.saveBatch(lessons);

    }

    /**
     * 1.分页查询我的课程
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> pageQueryMyLessons(PageQuery pageQuery) {

        //1.获取当前登陆人
        Long userID = UserContext.getUser();
        //2.发起分页查询

      /*  Page<LearningLesson> page = Page.of(pageQuery.getPageNo(), pageQuery.getPageSize());
       if(ObjectUtil.isEmpty(pageQuery.getSortBy())){
           page.addOrder(OrderItem.desc("latest_learn_time"));
       }else {
           page.addOrder(new OrderItem(pageQuery.getSortBy(), pageQuery.getIsAsc()));
       }*/

        Page<LearningLesson> pageResult = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userID)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = pageResult.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return PageDTO.empty(pageResult);
        }
        //3.收集课程ID，，远程调用方法
        Map<Long, CourseSimpleInfoDTO> courseInfomap = queryCourseInfoAnd2Map(records);
        //4.循环分页结果，将po list 转 vo list
        List<LearningLessonVO> volist = new ArrayList<>(records.size());
        for (LearningLesson lesson : records) {
            //4.1 拷贝po到vo
            LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
            //4.2获取课程特有信息（课程名称，封面，总课时数）
            CourseSimpleInfoDTO course = courseInfomap.get(lesson.getCourseId());
            vo.setCourseName(course.getName());
            vo.setCourseCoverUrl(course.getCoverUrl());
            vo.setSections(course.getSectionNum());


            volist.add(vo);
        }
        //5. 封装最终的pageDTO 并返回
        return PageDTO.of(pageResult, volist);
    }


    /**
     * 删除退费的信息（作业一）
     *
     * @param userId
     * @param courseIds
     */
    @Override
    public void removeLessons(Long userId, List<Long> courseIds) {

        // 添加空值检查
        if (userId == null || CollectionUtils.isEmpty(courseIds)) {
            return;
        }

        try {
            this.remove(new LambdaQueryWrapper<LearningLesson>()
                    .eq(LearningLesson::getUserId, userId)
                    .in(LearningLesson::getCourseId, courseIds));
        } catch (Exception e) {
            log.error("删除用户课程失败，userId={}, courseIds={}", userId, courseIds, e);
            throw new BizIllegalException("删除课程失败");
        }

    }

    /**
     * 根据id查询我的课程信息6（作业一）
     *
     * @param courseId
     */
    @Override
    public LearningLessonVO getByidLessons(long courseId) {
        //取主线程的id
        Long userID = UserContext.getUser();
        if (userID == null) {
            throw new BizIllegalException("用户未登录");
        }

        LearningLesson one = lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, userID)
                .one();

        if (one == null) {
            return null;
        }
        LearningLessonVO learningLessonVO = BeanUtils.copyBean(one, LearningLessonVO.class);


        return learningLessonVO;
    }

    /**
     * 查询正在学习的课程
     */
    @Override
    public LearningLessonVO getLessonsById() {
        //1.获取当前登录的用户
        Long userID = UserContext.getUser();
        //查询正在学习的课程
        LearningLesson lesson = lambdaQuery().eq(LearningLesson::getUserId, userID)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        //判断为不为空
        if (lesson == null) {
            return null;
        }
        //拷po到vo
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        //查询课程信息
        CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (cInfo == null) {
            throw new BadRequestException("课程不存在");
        }
        vo.setCourseName(cInfo.getName());
        vo.setCourseCoverUrl(cInfo.getCoverUrl());
        vo.setSections(cInfo.getSectionNum());
        //统计课表中的课程数量
        Integer courseAmount = lambdaQuery()
                .eq(LearningLesson::getUserId, userID)
                .count();
        vo.setCourseAmount(courseAmount);
        //查询小节信息
        List<CataSimpleInfoDTO> cataInfos = catalogueClient.batchQueryCatalogue(Collections.singleton(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(cataInfos)) {
            CataSimpleInfoDTO cataInfo = cataInfos.get(0);
            vo.setLatestSectionName(cataInfo.getName());
            vo.setLatestSectionIndex(cataInfo.getCIndex());
        }
        return vo;
    }

    /**
     * 检查课程是否有效（作业）
     *
     * @param courseId
     */
    @Override
    public Long getCourseByCourseId(Long courseId) {
        Long userID = UserContext.getUser();
        LearningLesson oneLesson = lambdaQuery().eq(LearningLesson::getUserId, userID)
                .eq(LearningLesson::getCourseId, courseId)
                .ne(LearningLesson::getStatus, LessonStatus.EXPIRED.getValue())
                .one();
        if (ObjectUtil.isEmpty(oneLesson)) {
            return null;
        }
        Long learningLessonCourseId = oneLesson.getCourseId();
        return learningLessonCourseId;
    }

    /**
     * 统计课程的学习人数（作业）
     *
     * @param courseId
     */
    @Override
    public Integer getCountByCourseId(Long courseId) {
        Integer count = lambdaQuery().eq(LearningLesson::getCourseId, courseId)
                .count();
        if (ObjectUtil.isEmpty(count)) {
            return 0;
        }

        return count;
    }

    /**
     * 收集课程ID，，远程调用
     *
     * @param records
     * @return
     */
    private Map<Long, CourseSimpleInfoDTO> queryCourseInfoAnd2Map(List<LearningLesson> records) {
        //3.发起远程调用，查询课程信息的信息（课程名称，封面，总课时数）
        //3.1 收集当前页面的所有课程ID集合
        Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        //3.2 发起远程调用
        List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(courseIds);
        //3.3健壮性判断
        if (ObjectUtil.isEmpty(courseInfoList)) {
            throw new BizIllegalException("课程信息不存在");
        }
        //3.4 创建一个Map，将课程ID作为key，CourseSimpleInfoDTO作为value
        //courseInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, course -> course));
        // courseInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));
        Map<Long, CourseSimpleInfoDTO> couseInMap = CollStreamUtil.toIdentityMap(courseInfoList, CourseSimpleInfoDTO::getId);
        return couseInMap;
    }


    /**
     * 创建或修改学习计划
     *
     * @param planDTO
     */
    @Override
    public void createPlans(LearningPlanDTO planDTO) {

        this.lambdaUpdate()
                .set(LearningLesson::getWeekFreq, planDTO.getFreq())
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .eq(LearningLesson::getCourseId, planDTO.getCourseId())
                .update();
    }
}
